package rjeutsky.xml.dom;

import java.util.LinkedList;
import java.util.List;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

import rjeutsky.models.CardThema;
import rjeutsky.models.CardType;
import rjeutsky.models.OldCard;
import rjeutsky.models.TypeEnum;
import rjeutsky.models.builders.ConcreteOldCardBuilder;
import rjeutsky.xml.common.Constants;
import rjeutsky.xml.common.TagNames;

public class DocumentTransformer {
	private List<OldCard> cards;
	
	private Document document;

	public void readDocument(){
		cards = new LinkedList<OldCard>();
		Node root = document.getFirstChild(); 
		NodeList cardElements = root.getChildNodes();
		for (int i = 0; i < cardElements.getLength(); ++i) {
			Node node = cardElements.item(i);
			if (node.getNodeType() == Node.ELEMENT_NODE) {
				cards.add(readCard(node));
			}
		}
	}
	
	public void writeDocument() throws ParserConfigurationException{
		document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
		Element root = document.createElement(TagNames.OLD_CARD_COLLECTION);
		document.appendChild(root);
		
		root.setAttribute("xmlns:xsi",
				XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
		root.setAttribute("xsi:noNamespaceSchemaLocation", Constants.SCHEMA_PATH);
		
		for (OldCard card : cards) {
			root.appendChild(buildCardElement(card));
		}
	}
	
	public List<OldCard> getCards() {
		return cards;
	}

	public void setCards(List<OldCard> cards) {
		this.cards = cards;
	}

	public Document getDocument() {
		return document;
	}

	public void setDocument(Document document) {
		this.document = document;
	}
	
	protected Element buildCardElement(OldCard card) {
		Element element = document.createElement(TagNames.OLD_CARD);

		element.appendChild(buildElementWithText(TagNames.THEMA, card.getThema().name()));
		element.appendChild(buildTypeElement(card.getType()));
		element.appendChild(buildElementWithText(TagNames.COUNTRY, card.getCountry()));
		element.appendChild(buildElementWithText(TagNames.YEAR, String.valueOf(card.getYear())));
		if (card.getAuthor() != null) {
			element.appendChild(buildElementWithText(TagNames.AUTHOR, card.getAuthor()));
		}
		
		if (card.getValuable() != null) {
			element.appendChild(buildElementWithText(TagNames.VALUABLE, card.getValuable()));
		}
		
		return element;

	}
	
	protected Element buildTypeElement(CardType type) {
		Element element = buildElementWithText(TagNames.CARD_TYPE, type.getType().name());
		element.setAttribute(TagNames.IS_SEND, String.valueOf(type.getIsSent()));
		return element;
	}
	
	protected Element buildElementWithText(String name, String text) {
		Element element = document.createElement(name);
		element.appendChild(document.createTextNode(text));
		return element;
	}

	protected OldCard readCard(Node element) {
		ConcreteOldCardBuilder builder = new ConcreteOldCardBuilder();
		NodeList childElements = element.getChildNodes();
		for (int i = 0; i < childElements.getLength(); ++i) {
			Node node = childElements.item(i);
			if (node.getNodeType() == Node.ELEMENT_NODE) {
				String tagName = node.getNodeName();
				if (tagName.equals(TagNames.THEMA)) {
					builder.setThema(CardThema.valueOf(getText(node)));
				} else if (tagName.equals(TagNames.CARD_TYPE)) {
					CardType type = new CardType();
					type.setType(TypeEnum.valueOf(getText(node)));
					String attributeText = node.getAttributes().getNamedItem(TagNames.IS_SEND).getNodeValue();
					type.setIsSent(Boolean.parseBoolean(attributeText));
					builder.setType(type);
				} else if (tagName.equals(TagNames.COUNTRY)) {
					builder.setCountry(getText(node));
				} else if (tagName.equals(TagNames.YEAR)) {
					builder.setYear(Integer.parseInt(getText(node)));
				} else if (tagName.equals(TagNames.AUTHOR)) {
					builder.setAuthor(getText(node));
				} else if (tagName.equals(TagNames.VALUABLE)) {
					builder.setValuable(getText(node));
				}
			}
		}

		builder.createNewCard();
		builder.buildAll();
		return builder.getCard();
	}
	
	protected String getText(Node node) {
		return ((Text) (node.getFirstChild())).getData();
	}
}
